package com.foftact.etfhist;

import com.alibaba.fastjson2.JSON;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONReader;
import com.foftact.etfhist.mapper.ETFHistoryMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * ETF历史净值服务实现类
 * 实现ETFHistoryService接口中的业务方法
 */
@Service
public class ETFHistoryServiceImpl implements ETFHistoryService {
    private static final Logger logger = LoggerFactory.getLogger(ETFHistoryServiceImpl.class);

    @Autowired
    private ETFHistoryMapper etfHistoryMapper;

    // ETF历史净值API接口模板
    private static final String ETF_HISTORY_API_TEMPLATE = "https://api.fund.eastmoney.com/f10/lsjz?callback=jQuery18307006029487505436_1757777731550&fundCode=%s&pageIndex=1&pageSize=20&startDate=&endDate=&_=1757777747258";

    // 数据来源标识
    private static final String DATA_SOURCE = "东方财富";

    /**
     * 抓取并保存指定基金代码的历史净值数据
     * @param fundCode 基金代码
     * @return 成功保存的记录数
     */
    @Override
    @Transactional
    public int fetchAndSaveETFHistoryData(String fundCode) {
        logger.info("开始抓取基金代码为{}的ETF历史净值数据", fundCode);
        try {
            // 1. 从API获取数据
            String jsonData = fetchETFHistoryDataFromApi(fundCode);
            if (jsonData == null || jsonData.isEmpty()) {
                logger.error("未获取到基金代码为{}的ETF历史净值数据", fundCode);
                return 0;
            }

            // 2. 解析JSON数据
            List<ETFHistory> etfHistoryList = parseETFHistoryData(fundCode, jsonData);
            if (etfHistoryList == null || etfHistoryList.isEmpty()) {
                logger.error("解析基金代码为{}的ETF历史净值数据失败", fundCode);
                return 0;
            }

            // 3. 按要求过滤需要保存的数据
            List<ETFHistory> dataToSave = filterDataToSave(fundCode, etfHistoryList);
            if (dataToSave.isEmpty()) {
                logger.info("基金代码为{}的ETF历史净值数据无需更新", fundCode);
                return 0;
            }

            // 4. 保存数据到数据库
            int savedCount = batchSaveETFHistory(dataToSave);
            logger.info("ETF历史净值数据抓取完成，基金代码为{}，共保存{}条记录", fundCode, savedCount);
            return savedCount;
        } catch (Exception e) {
            logger.error("抓取ETF历史净值数据异常，fundCode: {}", fundCode, e);
            throw new RuntimeException("抓取ETF历史净值数据异常", e);
        }
    }

    /**
     * 从API获取ETF历史净值数据
     * @param fundCode 基金代码
     * @return JSON格式的数据字符串
     */
    private String fetchETFHistoryDataFromApi(String fundCode) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String apiUrl = String.format(ETF_HISTORY_API_TEMPLATE, fundCode);
        HttpGet httpGet = new HttpGet(apiUrl);
        httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity, "UTF-8");
                // 去除JSONP的回调函数包装
                Pattern pattern = Pattern.compile("^\\w+\\((.*)\\)$");
                Matcher matcher = pattern.matcher(result);
                if (matcher.find()) {
                    return matcher.group(1);
                }
                return result;
            }
        } catch (IOException e) {
            logger.error("调用ETF历史净值API异常，fundCode: {}", fundCode, e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                logger.error("关闭HTTP客户端异常", e);
            }
        }
        return null;
    }

    /**
     * 解析ETF历史净值数据
     * @param fundCode 基金代码
     * @param jsonData JSON格式的数据字符串
     * @return ETF历史净值数据列表
     */
    private List<ETFHistory> parseETFHistoryData(String fundCode, String jsonData) {
        List<ETFHistory> etfHistoryList = new ArrayList<>();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        try {
            ETFHistoryResponseDTO responseDTO = JSON.parseObject(jsonData, ETFHistoryResponseDTO.class, JSONReader.Feature.AllowUnQuotedFieldNames);
            if (responseDTO != null && responseDTO.getData() != null) {
                List<ETFHistoryDTO> dtoList = responseDTO.getData().getLsjzList();
                if (dtoList != null && !dtoList.isEmpty()) {
                    for (ETFHistoryDTO dto : dtoList) {
                        ETFHistory etfHistory = convertToModel(fundCode, dto, dateFormat);
                        if (etfHistory != null) {
                            etfHistoryList.add(etfHistory);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析ETF历史净值数据异常，fundCode: {}", fundCode, e);
        }

        return etfHistoryList;
    }

    /**
     * 将DTO对象转换为Model对象
     * @param fundCode 基金代码
     * @param dto ETFHistoryDTO对象
     * @param dateFormat 日期格式化对象
     * @return ETFHistory对象
     */
    private ETFHistory convertToModel(String fundCode, ETFHistoryDTO dto, SimpleDateFormat dateFormat) {
        ETFHistory etfHistory = new ETFHistory();
        etfHistory.setFundCode(fundCode);
        etfHistory.setDataSource(DATA_SOURCE);

        try {
            // 转换净值日期
            if (dto.getFsrq() != null && !dto.getFsrq().isEmpty()) {
                etfHistory.setNavDate(dateFormat.parse(dto.getFsrq()));
            }

            // 转换单位净值
            if (dto.getDwjz() != null && !dto.getDwjz().isEmpty()) {
                etfHistory.setUnitNav(new BigDecimal(dto.getDwjz()));
            }

            // 转换累计净值
            if (dto.getLjjz() != null && !dto.getLjjz().isEmpty()) {
                etfHistory.setCumulativeNav(new BigDecimal(dto.getLjjz()));
            }

            // 转换日增长率
            if (dto.getJzzzl() != null && !dto.getJzzzl().isEmpty()) {
                etfHistory.setDailyGrowthRate(new BigDecimal(dto.getJzzzl()));
            }

            // 设置申购状态、赎回状态、分红送配
            etfHistory.setPurchaseStatus(dto.getSgzt());
            etfHistory.setRedemptionStatus(dto.getShzt());
            etfHistory.setDividendInfo(dto.getFhfcz());

        } catch (ParseException e) {
            logger.error("转换ETF历史净值数据异常，fundCode: {}, date: {}", fundCode, dto.getFsrq(), e);
            return null;
        } catch (NumberFormatException e) {
            logger.error("转换数值类型异常，fundCode: {}, data: {}", fundCode, dto, e);
            return null;
        }

        return etfHistory;
    }

    /**
     * 按要求过滤需要保存的数据
     * 要求1：按周判断数据是否已存在，如果该周数据已存在，则不写入。如果该周数据不存在或不完整，则写入更新该周所有数据。
     * 要求2：近3天数据，无论数据库是否存在都要更新。
     * @param fundCode 基金代码
     * @param etfHistoryList 解析后的ETF历史净值数据列表
     * @return 需要保存的数据列表
     */
    private List<ETFHistory> filterDataToSave(String fundCode, List<ETFHistory> etfHistoryList) {
        List<ETFHistory> dataToSave = new ArrayList<>();
        Date threeDaysAgo = DateUtil.offsetDay(new Date(), -3);

        for (ETFHistory etfHistory : etfHistoryList) {
            Date navDate = etfHistory.getNavDate();
            boolean needSave = false;

            // 检查是否为近3天数据
            if (navDate.after(threeDaysAgo) || navDate.equals(threeDaysAgo)) {
                needSave = true; // 近3天数据，无论是否存在都要更新
            } else {
                // 不是近3天数据，按周判断
                Calendar cal = Calendar.getInstance();
                cal.setTime(navDate);
                cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); // 设置为本周周一
                Date startOfWeek = cal.getTime();
                cal.add(Calendar.DAY_OF_WEEK, 6); // 加6天，得到周日
                Date endOfWeek = cal.getTime();

                // 查询该周数据是否存在且完整
                int count = etfHistoryMapper.countByFundCodeAndWeek(fundCode, startOfWeek, endOfWeek);
                // 假设一周最多5个交易日，如果记录数少于5，则认为数据不完整
                if (count < 5) {
                    needSave = true;
                }
            }

            if (needSave) {
                dataToSave.add(etfHistory);
            }
        }

        return dataToSave;
    }

    /**
     * 根据基金代码和净值日期查询ETF历史净值数据
     * @param fundCode 基金代码
     * @param navDate 净值日期
     * @return ETF历史净值数据对象
     */
    @Override
    public ETFHistory getETFHistoryByFundCodeAndDate(String fundCode, Date navDate) {
        try {
            return etfHistoryMapper.selectByFundCodeAndDate(fundCode, navDate);
        } catch (Exception e) {
            logger.error("根据基金代码和净值日期查询ETF历史净值数据异常，fundCode: {}, navDate: {}", fundCode, navDate, e);
            return null;
        }
    }

    /**
     * 根据基金代码和日期范围查询ETF历史净值数据
     * @param fundCode 基金代码
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return ETF历史净值数据列表
     */
    @Override
    public List<ETFHistory> getETFHistoryByFundCodeAndDateRange(String fundCode, Date startDate, Date endDate) {
        try {
            return etfHistoryMapper.selectByFundCodeAndDateRange(fundCode, startDate, endDate);
        } catch (Exception e) {
            logger.error("根据基金代码和日期范围查询ETF历史净值数据异常，fundCode: {}, startDate: {}, endDate: {}", 
                    fundCode, startDate, endDate, e);
            return new ArrayList<>();
        }
    }

    /**
     * 保存单个ETF历史净值数据
     * @param etfHistory ETF历史净值数据对象
     * @return 保存是否成功
     */
    @Override
    @Transactional
    public boolean saveETFHistory(ETFHistory etfHistory) {
        try {
            int result = etfHistoryMapper.insert(etfHistory);
            return result > 0;
        } catch (Exception e) {
            logger.error("保存ETF历史净值数据异常", e);
            return false;
        }
    }

    /**
     * 批量保存ETF历史净值数据
     * @param etfHistoryList ETF历史净值数据列表
     * @return 保存的记录数
     */
    @Override
    @Transactional
    public int batchSaveETFHistory(List<ETFHistory> etfHistoryList) {
        try {
            return etfHistoryMapper.batchInsert(etfHistoryList);
        } catch (Exception e) {
            logger.error("批量保存ETF历史净值数据异常", e);
            return 0;
        }
    }

    /**
     * 更新ETF历史净值数据
     * @param etfHistory ETF历史净值数据对象
     * @return 更新是否成功
     */
    @Override
    @Transactional
    public boolean updateETFHistory(ETFHistory etfHistory) {
        try {
            int result = etfHistoryMapper.updateByFundCodeAndDate(etfHistory);
            return result > 0;
        } catch (Exception e) {
            logger.error("更新ETF历史净值数据异常", e);
            return false;
        }
    }

    /**
     * 根据基金代码和净值日期删除ETF历史净值数据
     * @param fundCode 基金代码
     * @param navDate 净值日期
     * @return 删除是否成功
     */
    @Override
    @Transactional
    public boolean deleteETFHistoryByFundCodeAndDate(String fundCode, Date navDate) {
        try {
            int result = etfHistoryMapper.deleteByFundCodeAndDate(fundCode, navDate);
            return result > 0;
        } catch (Exception e) {
            logger.error("删除ETF历史净值数据异常，fundCode: {}, navDate: {}", fundCode, navDate, e);
            return false;
        }
    }

    /**
     * 根据基金代码删除所有ETF历史净值数据
     * @param fundCode 基金代码
     * @return 删除是否成功
     */
    @Override
    @Transactional
    public boolean deleteAllETFHistoryByFundCode(String fundCode) {
        try {
            int result = etfHistoryMapper.deleteByFundCode(fundCode);
            return result > 0;
        } catch (Exception e) {
            logger.error("删除所有ETF历史净值数据异常，fundCode: {}", fundCode, e);
            return false;
        }
    }

    /**
     * 清空ETF历史净值表
     * @return 操作是否成功
     */
    @Override
    @Transactional
    public boolean clearETFHistory() {
        try {
            etfHistoryMapper.truncateTable();
            return true;
        } catch (Exception e) {
            logger.error("清空ETF历史净值表异常", e);
            return false;
        }
    }
}